package io.traveller.common.mybatis;

import com.google.common.base.CaseFormat;
import io.traveller.common.util.CollectionUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Mybatis更新操作工具类
 *
 * Created by yunai on 16/8/4.
 */
public class Update {

    public static final Object NULL = new Object();

    private Map<String, Object> params = new HashMap<>();

    /**
     * 是否将驼峰转换成下换线.
     * 比如说, "orderCount" 转换为 "order_count"
     */
    private final boolean mapCamelCaseToUnderscore = true;

    /**
     * 从对象复制需要指定的变量, 创建Update
     *
     * @param obj 对象
     * @param fields 复制的变量
     * @return Update
     */
    public static Update copy(Object obj, String... fields) {
        Update update = new Update();
        for (String field : fields) {
            try {
                Object value = CollectionUtils.getField(obj, field).get(obj);
                update.set(field, value);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return update;
    }

    /**
     * 从对象复制需要指定的变量(排除null值), 创建Update
     *
     * @param obj 对象
     * @param fields 复制的变量
     * @return Update
     */
    public static Update copyWithoutNull(Object obj, String... fields) {
        Update update = new Update();
        for (String field : fields) {
            try {
                Object value = CollectionUtils.getField(obj, field).get(obj);
                if (null != value) {
                    update.set(field, value);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return update;
    }

    public Update set(String key, Object value) {
        if (mapCamelCaseToUnderscore) {
            key = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key);
        }
        //备注：传入Java中的null, 并且mapper中update有foreach，会导致mybatis解析sql报错, 此处传入特殊类型枚举
        //      在mapper中这么判断
        //            <when test="value == io.traveller.common.mybatis.Update.NULL">
        //                ${key} = NULL
        //            </when>
        if (null == value) {
            value = NULL;
        }
        params.put(key, value);
        return this;
    }

    /**
     * 为指定的keys设置为null
     *
     * @param keys
     * @return
     */
    public Update setNull(String... keys) {
        if (null == keys || keys.length == 0) {
            return this;
        }
        for (String key : keys) {
            set(key, null);
        }
        return this;
    }

    public Update incr(String key, int incrCount) {
        if (mapCamelCaseToUnderscore) {
            key = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, key);
        }
        if (incrCount > 0) {
            params.put(key, "+ " + incrCount);
        } else {
            params.put(key, "- " + incrCount);
        }
        return this;
    }

    public Set<Map.Entry<String, Object>> get() {
        return params.entrySet();
    }

    /**
     * 返回更新的字段的数组Field
     *
     * @return filed
     */
    public Field getField() {
        String[] fields = new String[params.keySet().size()];
        int i = 0;
        for (String field : params.keySet()) {
            fields[i++] = field;
        }
        return new Field(fields);
    }

    /**
     * 创建一个包含修改条件的Update对象
     *
     * @param key
     * @param value
     * @return
     */
    public static Update update(String key, Object value) {
        return new Update().set(key, value);
    }
}